//@version: $Id: Map.cpp 64 2010-11-25 20:46:39Z NeurobaticsTim@gmail.com $

#include "Map.h"
#ifdef _STANDALONE_MAP_H
#include <stdio.h>
#include <Windows.h>
#endif

void Map::clear() {
	//clear the entire combo list
	m_vMarkedCombos.clear();
}

const bool Map::comboCheck() {
	bool bComboFound = false;
	Shape * pvLastShape = &m_vGrid[0][0];
	unsigned int uiComboCounter = 0;

	//go through the map grid of shapes horizontally
	for(unsigned int uiY = 0; uiY < HEIGHT; ++uiY) {
		for(unsigned int uiX = 0; uiX < WIDTH; ++uiX) {
			//if last grid shape is the same type as this
			if(m_vGrid[uiY][uiX].getShapeTyp() == pvLastShape->getShapeTyp()) {
				//increase combo counter and if it's equal to COMBO_MAX
				if(++uiComboCounter == COMBO_MAX) {
					//then record combo as found
					bComboFound = true;
					//create a new combo list
					Combo vTemp;
					//go through the last COMBO_MAX number of shapes
					for(unsigned int uiI = 0; uiI < COMBO_MAX; ++uiI) {
						unsigned int uiTempCoord = uiX - uiI;
						//store the coordinates of the shapes
						vTemp.comboCoords[uiI].x = uiTempCoord;
						vTemp.comboCoords[uiI].y = uiY;
						//then store the shapes in the list
						vTemp.comboShapes[uiI] = &m_vGrid[uiY][uiTempCoord];
					}
					//add it to the combo list
					m_vMarkedCombos.add(vTemp);
					//and reset the combo counter
					uiComboCounter = 0;
				}
			}
			//else if grid shape is different type from last
			else
				//reset the combo counter
				uiComboCounter = 1;
			//set the last shape to this shape
			pvLastShape = &m_vGrid[uiY][uiX];
		}
		//reset the combo counter
		uiComboCounter = 1;
	}
	
	//reset the combo counter and last shape
	uiComboCounter = 0;
	pvLastShape = &m_vGrid[0][0];
	//go through the map grid of shapes vertically
	for(unsigned int uiX = 0; uiX < WIDTH; ++uiX) {
		for(unsigned int uiY = 0; uiY < HEIGHT; ++uiY) {
			//if last grid shape is the same type as this
			if(m_vGrid[uiY][uiX].getShapeTyp() == pvLastShape->getShapeTyp()) {
				//increase combo counter and if it's equal to COMBO_MAX
				if(++uiComboCounter == COMBO_MAX) {
					//then record combo as found
					bComboFound = true;
					//create a new combo list
					Combo vTemp;
					//go through the last COMBO_MAX number of shapes
					for(unsigned int uiI = 0; uiI < COMBO_MAX; ++uiI) {
						unsigned int uiTempCoord = uiY - uiI;
						//store the coordinates of the shapes
						vTemp.comboCoords[uiI].x = uiX;
						vTemp.comboCoords[uiI].y = uiTempCoord;
						//then store the shapes in the list
						vTemp.comboShapes[uiI] = &m_vGrid[uiTempCoord][uiX];
					}
					//add it to the combo list
					m_vMarkedCombos.add(vTemp);
					//and reset the combo counter
					uiComboCounter = 0;
				}
			}
			//else if grid shape is different type from last
			else
				//reset the combo counter
				uiComboCounter = 1;
			//set the last shape to this shape
			pvLastShape = &m_vGrid[uiY][uiX];
		}
		//reset the combo counter
		uiComboCounter = 1;
	}
	//return true if combo is found
	return bComboFound;
}

const bool Map::comboCheckQuick() {
	bool bComboFound = false;
	Shape * pvLastShape = &m_vGrid[0][0];
	unsigned int uiComboCounter = 0;

	//go through the map grid of shapes horizontally
	for(unsigned int uiY = 0; uiY < HEIGHT && !bComboFound; ++uiY) {
		for(unsigned int uiX = 0; uiX < WIDTH && !bComboFound; ++uiX) {
			//if last grid shape is the same type as this
			if(m_vGrid[uiY][uiX].getShapeTyp() == pvLastShape->getShapeTyp()) {
				//increase combo counter and if it's equal to COMBO_MAX
				if((++uiComboCounter) == COMBO_MAX)
					//then record combo as found
					bComboFound = true;
			}
			//else if grid shape is different type from last
			else
				//reset the combo counter
				uiComboCounter = 1;
			//set the last shape to this shape
			pvLastShape = &m_vGrid[uiY][uiX];
		}
		//reset the combo counter
		uiComboCounter = 1;
	}
	
	//reset the combo counter and last shape
	uiComboCounter = 0;
	pvLastShape = &m_vGrid[0][0];
	//go through the map grid of shapes vertically
	for(unsigned int uiX = 0; uiX < WIDTH && !bComboFound; ++uiX) {
		for(unsigned int uiY = 0; uiY < HEIGHT && !bComboFound; ++uiY) {
			//if last grid shape is the same type as this
			if(m_vGrid[uiY][uiX].getShapeTyp() == pvLastShape->getShapeTyp()) {
				//increase combo counter and if it's equal to COMBO_MAX
				if((++uiComboCounter) == COMBO_MAX)
					//then record combo as found
					bComboFound = true;
			}
			//else if grid shape is different type from last
			else
				//reset the combo counter
				uiComboCounter = 1;
			//set the last shape to this shape
			pvLastShape = &m_vGrid[uiY][uiX];
		}
		//reset the combo counter
		uiComboCounter = 1;
	}
	//return true if combo is found
	return bComboFound;
}

const bool Map::swapQuick(const unsigned int & a_uiAx, const unsigned int & a_uiAy, const unsigned int & a_uiBx, const unsigned int & a_uiBy) {
	//if any coordinates are out of bounds
	if(a_uiAx >= WIDTH || a_uiBx >= WIDTH || a_uiAy >= HEIGHT || a_uiBy >= HEIGHT)
		//return as failure to swap
		return false;
	//store shape A temporarily in a temp variable
	Shape vTemp = m_vGrid[a_uiAy][a_uiAx];
	//set shape A to shape B
	m_vGrid[a_uiAy][a_uiAx] = m_vGrid[a_uiBy][a_uiBx];
	//set shape B to shape A
	m_vGrid[a_uiBy][a_uiBx] = vTemp;

	//return as successful swap
	return true;
}

void Map::handleClickInput() {
	Location vDifference;
	Location vFirstClick, vSecondClick;
	bool bSwapPossible;

	//record the first two clicks
	vFirstClick = m_vClickBuffer[0].mouseClick();
	vSecondClick = m_vClickBuffer[1].mouseClick();
	//record the difference between the first two clicks
	vDifference.x = vSecondClick.x - vFirstClick.x;
	vDifference.y = vSecondClick.y - vFirstClick.y;
	//set swap possible only if clicks are seperate from each other, and next to each other horizontally or vertically
	bSwapPossible = ((!vDifference.x || vDifference.x == 1 || vDifference.x == -1) && (!vDifference.y || vDifference.y == 1 || vDifference.y == -1));
	bSwapPossible &= ((vDifference.x != NULL) ^ (vDifference.y != NULL));
	//if swap possible
	if(bSwapPossible) {
#ifdef _STANDALONE_MAP_H
		if(
#endif
		//then swap based on the two clicks
		swap(vFirstClick.x, vFirstClick.y, vSecondClick.x, vSecondClick.y)
#ifdef _STANDALONE_MAP_H
		)
			printf("Swap successful.\n");
		else
			printf("Swap not possible.\n");
#else
		;
#endif
	}
#ifdef _STANDALONE_MAP_H
	else
		printf("Swap not possible.\n");
#endif
}



Map::Map() : m_uiCurrentClick(0) {}
Map::~Map() {}



const bool Map::init() {
	//TODO: Initiate the map

#ifdef _STANDALONE_MAP_H
	for(unsigned int uiY = 0; uiY < HEIGHT; ++uiY)
		for(unsigned int uiX = 0; uiX < WIDTH; ++uiX)
			m_vGrid[uiY][uiX].type = (ShapeType)(rand()%SHAPE_SIZE);
#endif

	return true;
}

const bool Map::swap(const unsigned int & a_uiAx, const unsigned int & a_uiAy, const unsigned int & a_uiBx, const unsigned int & a_uiBy) {
	//if any coordinates are out of bounds
	if(a_uiAx >= WIDTH || a_uiBx >= WIDTH || a_uiAy >= HEIGHT || a_uiBy >= HEIGHT)
		//return as failure to swap
		return false;
	//store shape A temporarily in a temp variable
	Shape vTemp = m_vGrid[a_uiAy][a_uiAx];
	//set shape A to shape B
	m_vGrid[a_uiAy][a_uiAx] = m_vGrid[a_uiBy][a_uiBx];
	//set shape B to shape A
	m_vGrid[a_uiBy][a_uiBx] = vTemp;

	//TODO: swap local locations and other miscellaneous data for the shapes based on the memory swap to the actual shapes

	//return as successful swap
	return true;
}

const bool Map::check() {
	bool bCombosPossible = false;

	//go through each shape in the map
	for(unsigned int uiY = 0; uiY < HEIGHT && !bCombosPossible; ++uiY) {
		for(unsigned int uiX = 0; uiX < WIDTH && !bCombosPossible; ++uiX) {
			//go through horizontal and vertical phases of swapping per current shape
			for(unsigned int uiSwapDirection = HORIZONTAL; uiSwapDirection < COMBO_SIZE && !bCombosPossible; ++uiSwapDirection) {

				//record values for horizontal and vertical phases
				unsigned int uiHorizontal = uiX + ((COMBO_SIZE-1)-uiSwapDirection);
				unsigned int uiVertical = uiY + uiSwapDirection;

				//swap the current shape horizontally or vertically (dependent on the phase)
				//   Note: Does not swap if values are out of bounds (internal in swapQuick function)
				if(swapQuick(uiX, uiY, uiHorizontal, uiVertical)) {
					//if successful, do a check for new combos
					if(comboCheckQuick())
						//set combos as possible if new combo found
						bCombosPossible = true;
					//swap the current shape back to its position
					swapQuick(uiX, uiY, uiHorizontal, uiVertical);
				}
			}
		}
	}

	//return true if combos are possible
	return bCombosPossible;
}

void Map::fill() {
	for(int j = 0; j < m_vMarkedCombos.size(); j++)
	{
        //Starts the current combination. Because there may be more than one combo.
        MapCoord * currentPoint = m_vMarkedCombos.get(j).comboCoords;
        //Puts the current set of coordinates into a pointer for easier access.
        for(int i = COMBO_MAX-1; i >= 0; i--)
        {
            //Sets it to go backwards through the coordinates, forwards creates a bug (has to do with way coordinates are set.)
            for(int k = currentPoint[i].y; k >= 0; k--)
            {
                m_vGrid[k][currentPoint[i].x] = m_vGrid[k-1][currentPoint[i].x];
                //"Hey, you're above me, GO RIGHT HERE." "Ok." - two random shapes, one of which is in a combination.
            }
			Shape * temp = &m_vGrid[0][currentPoint[i].x];
			temp->setShapeType(temp->generate());
            //Randomizes the shape that's at Y coordinate 0.
        }
    }
}

const bool Map::comboRenew() {
	bool bCombosReplaced;

	//if there are shape combos available
	if(bCombosReplaced = comboCheck()) {
		//fill in the voids with new shapes
		fill();
		//clear the combo shapes
		clear();
	}

	return bCombosReplaced;
}

void Map::handleInput(UserInput a_vUI)
{
	/* === New Code === */
	//take in next mouse click
	//   Note: Expect this code to change to be able to accept different UI types, other than mouse
	//      Ex: a_vUI.getType() == KEYBOARD
	m_vClickBuffer[m_uiCurrentClick++] = a_vUI;
	m_uiCurrentClick%=CLICK_MAX;

	//if max clicks were reached
	//   Note: Expect this code to change to use flag system with switch
	if(!m_uiCurrentClick)
		//then handle the clicks
		handleClickInput();
	/*
	//else if max clicks not reached
	else
		//go through all shapes clicked on
		for(unsigned int i = 0; i < m_uiCurrentClick; ++i)
			//and rotate them
			//TODO: Account for shapes that are already rotating
			m_vGrid[m_vClickBuffer[i].mouseClick().y][m_vClickBuffer[i].mouseClick().x].rotate();
	*/

	/* === Old Code === */
	/*
	//track amount of clicks. Since there is only two, a static boolean will be good enough.
	static bool amountOfClicks = false; //Set it to none.
	//Tracks grid coordinates of two shapes. Since Shape hasn't gotten all their stuff done yet, four static ints will handle it. For now.
	static int a_X = 0, a_Y = 0, b_X = 0, b_Y = 0;
	//First it needs to handle keyboard presses. Such as Q for quit or something similar.
	//if(ui.keyboardPress() != 0) //I am unsure if this is the way I need to do this or not.
	//{
	//	switch(ui.keyboardPress())
	//	{
	//	case 'q':
	//	case 'Q':
	//		//put in quit case here. Unless this is UI's job.
	//		break;
	//	}
	//}
	
	if(!amountOfClicks) //They've only clicked once. Somewhere.
	{
		//a_X = ui.getLocationOfMouse().x;
		//a_Y = ui.getLocationOfMouse().y;
		a_X = a_vUI.x;
		a_Y = a_vUI.y;
		amountOfClicks = true;
		//m_vGrid[a_X][a_Y].rotate();
		//To be uncommented once Shape gets their stuff done. That is when it rotates.
	}
	else
	{
		//They've clicked twice, a new second time.
		b_X = a_vUI.x;
		b_Y = a_vUI.y;
		amountOfClicks = false;

		//Checks to see if they're next to each other.
		if(a_X == b_X && ((a_Y-1) == b_Y || (a_Y+1) == b_Y))
		{
			//They are next to each other. Right now it accepts diagonals, get rid of that.
			//TODO: Not allow diagonals.
			swap(a_X, a_Y, b_X, b_Y);
		}
		else if(a_Y == b_Y && ((a_X+1) == b_X || (a_X-1) == b_X))
		{
			swap(a_X, a_Y, b_X, b_Y);
		}
		//If they're not next to each other, set everything back to normal. Even if they are, do the swap and stop everything.
		//m_vGrid[a_X][a_Y].rotate(); //Stop the rotation.
		a_X = 0; a_Y = 0; b_X = 0; b_Y = 0;
	}
	*/
}


#ifdef _STANDALONE_MAP_H

void Map::draw() {
	char szBuffer[BUFFER_SIZE];
	for(unsigned int uiI = 0; uiI < BUFFER_SIZE; ++uiI)
		szBuffer[uiI] = 0;

	for(unsigned int uiY = 0; uiY < HEIGHT; ++uiY) {
		for(unsigned int uiX = 0; uiX < WIDTH; ++uiX)
			szBuffer[uiY*(WIDTH+1) + uiX] = m_vGrid[uiY][uiX].getShapeTyp() + 224;
		szBuffer[(uiY+1)*(WIDTH+1)-1] = '\n';
	}

	printf("%s", szBuffer);
}

#endif